home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / OS / ZBootStrap.cpp < prev    next >
Text File  |  1997-08-16  |  9KB  |  382 lines

  1. /*
  2.  *  File:       ZBootStrap.cpp
  3.  *  Summary:       An object used to initialize and terminate an application.
  4.  *  Written by: Jesse Jones
  5.  *
  6.  *  Copyright ゥ 1996-1997 Jesse Jones. 
  7.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  8.  *
  9.  *  Change History (most recent first):    
  10.  *
  11.  *         <8>     8/16/97    JDJ        Boot calls InitContextualMenus.
  12.  *         <7>     8/06/97    JDJ        Sucky Mac alert uses StandardAlert. OnSystemNeeds
  13.  *                                    uses REQUIRES_APPEARANCE_MGR.
  14.  *         <6>     8/03/97    JDJ        Calls RegisterAppearanceClient.
  15.  *         <5>     6/20/97    JDJ        FragInit traps exceptions.
  16.  *         <4>     4/13/97    JDJ        FragTerm calls MExitAction::DoExitActions().
  17.  *         <3>     3/27/97    JDJ        Commented out call to __destroy_global_chain
  18.  *                                    (MSL C++ 2.1.1 calls it for us).
  19.  *         <2>     3/24/97    JDJ        Dtor checks for CW 11.1
  20.  *         <1>    10/27/96    JDJ        Created (from ZAppBootStrap)
  21.  */
  22.  
  23. #include <ZBootStrap.h>
  24.  
  25. #include <Appearance.h>
  26. #include <CodeFragments.h>
  27. #include <ContextualMenu.h>
  28. #include <Dialogs.h>
  29. #include <Fonts.h>
  30. #include <List.h>
  31. #include <TextEdit.h>
  32.  
  33. #include <ZConstants.h>
  34. #include <ZDebug.h>
  35. #include <ZExceptions.h>
  36. #include <ZExitAction.h>
  37. #include <ZGestalt.h>
  38. #include <ZMiscUtils.h>
  39. #include <ZStringUtils.h>
  40.  
  41. #if RAVEN_OPERATOR_NEW
  42. #include <ZMemoryHeap.h>
  43. #include <ZNewAndDelete.h>
  44. #endif
  45.  
  46.  
  47. //-----------------------------------
  48. //    Static Globals
  49. //
  50. static bool sInited  = false;
  51.  
  52.  
  53. // ===================================================================================
  54. //    Internal Functions
  55. // ===================================================================================
  56.  
  57. extern "C" void __destroy_global_chain();
  58.  
  59. //---------------------------------------------------------------
  60. //
  61. // InitializeToolbox
  62. //
  63. //---------------------------------------------------------------
  64. static void InitializeToolbox()
  65. {
  66.     MaxApplZone();                    // MoreMasters should be called in DoEarlyInit
  67.     
  68.     InitGraf((Ptr) &qd.thePort);        
  69.     InitFonts();
  70.     InitWindows();
  71.     InitMenus();
  72.     TEInit();
  73.     InitDialogs(nil);
  74. }
  75.  
  76.  
  77. //---------------------------------------------------------------
  78. //
  79. // FragInit
  80. //
  81. // Entry point for the application's fragment. This is called 
  82. // before static constructors, so it's a good place to perform
  83. // any critical initialization.
  84. //
  85. //---------------------------------------------------------------
  86. #pragma profile off
  87. extern "C" OSErr FragInit(CFragInitBlock);
  88. OSErr FragInit(CFragInitBlock block)
  89. {
  90.     #pragma unused(block)
  91.     
  92.     OSStatus err = noErr;
  93.         
  94.     InitializeToolbox();
  95.         
  96.     try {
  97.         TBootStrap::DoEarlyInit();
  98.  
  99. #if RAVEN_OPERATOR_NEW
  100.         ASSERT(gObjectHeap != nil);        // Create this in DoEarlyInit
  101. #endif
  102.  
  103.         sInited = true;
  104.         
  105.     // ・・・ハNote that these catch blocks are never executed: if an
  106.     // ・・・ハexception is thrown the program immediately terminates.
  107.     // ・・・ハI think this is happening because FragInit is called
  108.     // ・・・ハbefore __start has a chance to initialize the exception
  109.     // ・・・ハcode. I experimented with calling __register_fragment
  110.     // ・・・ but then throw did nothing and the app crashed.
  111. #if 0
  112.     } catch (const TMemoryException& e) {
  113.         ReportError(LoadRavenString("Initialization failed because"), e);
  114.         err = memFullErr;
  115.  
  116.     } catch (const TSystemException& e) {
  117.         ReportError(LoadRavenString("Initialization failed because"), e);
  118.         err = e.mError;
  119.                 
  120.     } catch (const TBaseException& e) {
  121.         ReportError(LoadRavenString("Initialization failed because"), e);
  122.         err = -1;
  123.  
  124.     } catch (...) {
  125.         ReportError(LoadRavenString("Initialization failed because of an unknown error"));
  126.         err = -1;
  127.     }
  128. #else
  129.     } catch (const TSystemException& e) {
  130.         err = e.mError;
  131.                 
  132.     } catch (...) {
  133.         err = -1;
  134.     }
  135. #endif    
  136.  
  137.     return (OSErr) err;
  138. }
  139. #pragma profile reset
  140.  
  141.  
  142. //---------------------------------------------------------------
  143. //
  144. // FragTerm
  145. //
  146. // Exit point for the application's fragment. This is called 
  147. // after static constructors, so it's a good place to do leak
  148. // checking.
  149. //
  150. //---------------------------------------------------------------
  151. #pragma profile off
  152. extern "C" void FragTerm();
  153. void FragTerm()
  154. {
  155.     // The release notes for System 7.6 say that A5 can be incorrect
  156.     // for earlier Systems when ExitToShell is called. To avoid any
  157.     // problems we'll make sure A5 is correct.
  158.     long oldA5 = SetCurrentA5();
  159.  
  160.     if (TBootStrap::Exiting()) {            // don't bother with leaks if we're terminating abnormally
  161. #if DEBUG
  162.         ulong leaks = 0;
  163.  
  164. #if RAVEN_OPERATOR_NEW
  165.         leaks = gObjectHeap->GetLeakCount();
  166.         if (leaks > 0)
  167.             gObjectHeap->DumpLeaks();
  168.     
  169. #elif DEBUG_NEW > DEBUG_NEW_BASIC    
  170.         leaks = gDebugNewAllocCount;
  171.         if (leaks > 0)
  172.             DebugNewReportLeaks();
  173. #endif
  174.  
  175.         if (leaks > 0)
  176.             DEBUGSTR("You have %d memory leaks: check the leaks.log file.", leaks);
  177. #endif
  178.  
  179.     } else
  180.         MExitAction::DoExitActions();        // terminating abnormally so call exit actions
  181.  
  182.     SetA5(oldA5);
  183. }
  184. #pragma profile reset
  185.  
  186.  
  187. //---------------------------------------------------------------
  188. //
  189. // MyNewHandler
  190. //
  191. // ・・・ハRemove this when new throws and we can move to ANSI exceptions.
  192. //
  193. //---------------------------------------------------------------
  194. static void MyNewHandler()
  195. {
  196.     throw TMemoryException();
  197. }
  198.  
  199. #pragma mark -
  200.  
  201. // ===================================================================================
  202. //    class TBootStrap
  203. // ===================================================================================
  204.  
  205. bool TBootStrap::msRunning = false;
  206. bool TBootStrap::msExiting = false;
  207.  
  208. //---------------------------------------------------------------
  209. //
  210. // TBootStrap::~TBootStrap
  211. //
  212. //---------------------------------------------------------------
  213. TBootStrap::~TBootStrap()
  214. {
  215.     msExiting = true;                    // terminating normally
  216.     
  217.     msRunning = false;
  218.     
  219. //    __destroy_global_chain();            // MSL C++ 2.1.1 handles this correctly        
  220. }
  221.  
  222.  
  223. //---------------------------------------------------------------
  224. //
  225. // TBootStrap::TBootStrap
  226. //
  227. //---------------------------------------------------------------
  228. TBootStrap::TBootStrap()
  229. {
  230.     ::FlushEvents(everyEvent, 0);
  231. }
  232.  
  233.  
  234. //---------------------------------------------------------------
  235. //
  236. // TBootStrap::Running                                    [static]
  237. //
  238. //---------------------------------------------------------------
  239. bool TBootStrap::Running()
  240. {
  241.     return msRunning;
  242. }
  243.  
  244.  
  245. //---------------------------------------------------------------
  246. //
  247. // TBootStrap::Exiting                                    [static]
  248. //
  249. //---------------------------------------------------------------
  250. bool TBootStrap::Exiting()
  251. {
  252.     return msExiting;
  253. }
  254.  
  255.  
  256. //---------------------------------------------------------------
  257. //
  258. // TBootStrap::Boot
  259. //
  260. //---------------------------------------------------------------
  261. void TBootStrap::Boot()
  262. {
  263.     ASSERT(sInited);                    // Need to use FragInit and FragTerm entry points!
  264.  
  265.     InitCursor();
  266.     
  267.     set_new_handler(MyNewHandler);
  268.  
  269.     UGestalt::Init();
  270.     
  271.     if (UGestalt::hasAppearanceMgr)
  272.         RegisterAppearanceClient();
  273.  
  274.     if (UGestalt::hasContextMenus) {
  275.         OSStatus err = InitContextualMenus();
  276.         if (err != noErr) {
  277.             UGestalt::hasContextMenus = false;
  278.             DEBUGSTR("InitContextualMenus returned %d", err);
  279.         }
  280.     }
  281.  
  282. #ifdef __PowerPlant__
  283.     UQDGlobals::SetQDGlobals(&qd);
  284. #endif
  285.  
  286.     this->HandleSystemCheck();
  287.         
  288.     this->OnBoot();
  289.     
  290.     msRunning = true;
  291. }
  292.  
  293.  
  294. //---------------------------------------------------------------
  295. //
  296. // TBootStrap::HandleSystemCheck
  297. //
  298. //---------------------------------------------------------------
  299. void TBootStrap::HandleSystemCheck()
  300. {
  301.     list<string, allocator<string> > needs;
  302.     
  303.     // Find out what the system is missing.
  304.     this->OnSystemNeeds(needs);
  305.     
  306.     if (needs.size() > 0) {
  307.     
  308.         // Build a string containing all of the reasons the app won't run.
  309.         string mesg;
  310.         if (needs.size() == 1)
  311.             mesg += needs.front();
  312.         
  313.         else if (needs.size() == 2)
  314.             mesg += needs.front() + LoadRavenString(" and ") + needs.back();
  315.         
  316.         else {
  317.             list<string, allocator<string> >::iterator iter = needs.begin();
  318.             while (iter != needs.end()) {
  319.                 string item = *iter++;
  320.                 
  321.                 if (iter == needs.end())
  322.                     mesg += LoadRavenString("and ");
  323.                 mesg += item;
  324.                 if (iter != needs.end())
  325.                     mesg += LoadRavenString(", ");
  326.             }
  327.         }
  328.  
  329.         // Put up an alert to let the user know how badly their Mac sucks.
  330.         InitCursor();
  331.  
  332.         if (UGestalt::hasAppearanceMgr) {
  333.             AlertStdAlertParamRec params;
  334.             params.movable       = false;
  335.             params.helpButton    = false;
  336.             params.filterProc    = nil;
  337.             params.defaultText   = StrToPStr(LoadRavenString("Quit"));
  338.             params.cancelText    = nil;
  339.             params.otherText     = nil;
  340.             params.defaultButton = ok;
  341.             params.cancelButton  = 0;
  342.             params.position      = kWindowDefaultPosition;
  343.             
  344.             string errorStr = LoadRavenString("Unable to run the app.");
  345.     
  346.             short item;
  347.             OSErr err = StandardAlert(kAlertStopAlert, StrToPStr(errorStr), StrToPStr(mesg), ¶ms, &item);
  348.             ASSERT(err == noErr);                        // seems kind of pointless to throw
  349.         
  350.         } else {
  351.             ParamText(StrToPStr(mesg), "¥p", "¥p", "¥p");
  352.             (void) ::Alert(129, nil);
  353.         }
  354.         
  355.         // Bail
  356.         ::ExitToShell();
  357.     }
  358. }
  359.  
  360.  
  361. //---------------------------------------------------------------
  362. //
  363. // TBootStrap::OnSystemNeeds
  364. //
  365. //---------------------------------------------------------------
  366. void TBootStrap::OnSystemNeeds(list<string, allocator<string> >& needs)
  367. {
  368.     if (UGestalt::systemVersion < 0x00700)
  369.         needs.push_back(LoadRavenString("System 7"));                    
  370.         
  371.     if (!UGestalt::hasColorQD)
  372.         needs.push_back(LoadRavenString("Color QuickDraw"));
  373.         
  374. #if REQUIRES_APPEARANCE_MGR
  375.     if (!UGestalt::hasAppearanceMgr)
  376.         needs.push_back(LoadRavenString("the Appearance Manager"));
  377. #endif
  378. }
  379.  
  380.  
  381.  
  382.